import serial


SOH = 0x01
STX = 0x02
EOT = 0x04
ACK = 0x06
NAK = 0x15
C = b'C'

# For CRC algorithm
CRC_TA16 = [0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
            0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef]


class YMODEM(object):
    def bytesToInt(self, bytes):
        result = 0
        for b in bytes:
            result = result * 256 + int(b)
        return result

    def intToBytes(self, value, length):
        result = []
        for i in range(0, length):
            result.append(value >> (i * 8) & 0xff)
        result.reverse()
        return result

    def crc16(self, p_Data):
        crc = 0
        for x in p_Data:
            da = ((crc >> 8) & 0xFF) >> 4
            crc <<= 4
            crc ^= CRC_TA16[da ^ (x >> 4)]
            da = ((crc >> 8) & 0xFF) >> 4
            crc <<= 4
            crc ^= CRC_TA16[da ^ (x & 0x0f)]
            crc = crc & 0xffff
        crch = (crc>>8)
        crcl = (crc&0xFF)
        return crch, crcl

    def __init__(self):
        super().__init__()

        # 打开串口
        ser = serial.Serial(port='COM5', baudrate=115200, bytesize=8, parity='N', stopbits=1)
        if ser.isOpen():
            print("serial opened success")
        else:
            print("serial opened fail")

        # 检查Ymodem
        while True:
            cc = ser.read(1)
            if cc == C:
                break

        # 发送起始帧
        s1 = [SOH, 0, 0xFF]
        s2 = [0x6C,0x65,0x64,0x2E,0x62,0x69,0x6E,0x00,0x33,0x31,0x30,0x30,0x20,0x31,0x34,0x30,0x30,0x31,0x36,0x30,0x35,0x33,0x33,0x34,0x20,0x31,0x30,0x30,0x36,0x34,0x34]+[0]*97
        s2.extend(self.crc16(s2))
        ser.write(s1 + s2)
        while True:
            # 等待回应
            cc = ser.read(1)
            if cc == b'\x06':
                break

        # 读文件
        file = open('LED.bin', 'rb')
        j = 0
        breadstatus = 0
        while True:
            j += 1
            aa = [SOH, j, 255-j]
            cc = []
            for i in range(128):
                rf = file.read(1)
                if rf == b'':
                    rf = b'\x1A'
                    breadstatus = 1
                cc.extend(rf)
            cc.extend(self.crc16(cc))
            ser.write(aa + cc)
            # print(aa + cc)
            if breadstatus == 1:
                break
            while True:
                if ser.read(1) == b'\x06':
                    break

        while True:
            ser.write(b'\x04')
            cc = ser.read(1)
            if cc == b'\x15':
                break

        while True:
            ser.write(b'\x04')
            cc = ser.read(1)
            if cc == b'\x06':
                break

        # 发送结束帧
        s1 = [SOH, 0, 0xFF]
        s2 = [0] * 128
        s2.extend(self.crc16(s2))
        ser.write(s1 + s2)
        while True:
            # 等待回应
            cc = ser.read(1)
            if cc == b'\x06':
                break


if __name__ == '__main__':
    YMODEM()







